

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.sql.*;
import java.util.*;

import javax.swing.border.*;
import javax.swing.event.*;
import java.awt.event.*;

/**
 * A GUI JPanel for Requesting an Appointment
 */
public class GUI_PatientRequestAppointmentPanel extends JPanel
{
    private JButton           prevYearButton;
    private JButton           prevMonthButton;
    private JLabel            currentMonthYearLabel;
    private JButton           nextMonthButton;
    private JButton           nextYearButton;
    private JButton[]         dayButtons;
    private JRadioButton[]    timeButtons;
    private ButtonGroup       timeButtonsGroup;
    private Calendar          calendarView;
    private Calendar          calendarChosen;
    private JLabel            currentChosenDateLabel;
    private JPanel            calendarPanel;

    private JTextArea         appointmentReasonField;
    private JScrollPane       appointmentReasonPanel;
    private JTextField        desiredDoctorField;
    private JPanel            desiredDoctorPanel;
    private JButton           submitButton;
    private JButton           cancelButton;

    /**
     * Creates a new instance of GUI_PatientRequestAppointmentPanel
     */
    public GUI_PatientRequestAppointmentPanel()
    {
        calendarView = new GregorianCalendar();
        calendarChosen = new GregorianCalendar();

        prevYearButton = new JButton("\u21C7");
        prevYearButton.setToolTipText("Go to previous year");
        prevYearButton.addActionListener(new CalendarViewChangeActionListener(Calendar.YEAR, false));
        prevMonthButton = new JButton("\u2190");
        prevMonthButton.setToolTipText("Go to previous month");
        prevMonthButton.addActionListener(new CalendarViewChangeActionListener(Calendar.MONTH, false));
        currentMonthYearLabel = new JLabel(calendarView.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US) + " " + calendarView.get(Calendar.YEAR));
        currentMonthYearLabel.setHorizontalAlignment(JLabel.CENTER);
        nextMonthButton = new JButton("\u2192");
        nextMonthButton.setToolTipText("Go to next month");
        nextMonthButton.addActionListener(new CalendarViewChangeActionListener(Calendar.MONTH, true));
        nextYearButton = new JButton("\u21C9");
        nextYearButton.setToolTipText("Go to next year");
        nextYearButton.addActionListener(new CalendarViewChangeActionListener(Calendar.YEAR, true));

        dayButtons = new JButton[]
        { new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(),
          new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(),
          new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(),
          new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(),
          new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(),
          new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton(), new JButton() };
        timeButtons = new JRadioButton[]
        { new JRadioButton("9:00 am"), new JRadioButton("9:30 am"),
          new JRadioButton("10:00 am"), new JRadioButton("10:30 am"),
          new JRadioButton("11:00 am"), new JRadioButton("11:30 am"),
          new JRadioButton("12:00 pm"), new JRadioButton("12:30 pm"),
          new JRadioButton("1:00 pm"), new JRadioButton("1:30 pm"),
          new JRadioButton("2:00 pm"), new JRadioButton("2:30 pm"),
          new JRadioButton("3:00 pm"), new JRadioButton("3:30 pm"),
          new JRadioButton("4:00 pm"), new JRadioButton("4:30 pm") };
        timeButtonsGroup = new ButtonGroup();
        clearFields();

        currentChosenDateLabel = new JLabel("Date/time: " + calendarChosen.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US) + " "
                                                          + calendarChosen.get(Calendar.DAY_OF_MONTH) + ", "
                                                          + calendarChosen.get(Calendar.YEAR) + " @ "
                                                          + calendarChosen.get(Calendar.HOUR_OF_DAY) + ":"
                                                          + (calendarChosen.get(Calendar.MINUTE) < 10 ? "0" + calendarChosen.get(Calendar.MINUTE)
                                                                                                      : calendarChosen.get(Calendar.MINUTE)));

        calendarPanel = new JPanel();
        calendarPanel.setLayout(new GridBagLayout());
        calendarPanel.add(prevYearButton,        GUI_Main.constraints(0, 0, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(prevMonthButton,       GUI_Main.constraints(1, 0, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(currentMonthYearLabel, GUI_Main.constraints(2, 0, 3, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(nextMonthButton,       GUI_Main.constraints(5, 0, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(nextYearButton,        GUI_Main.constraints(6, 0, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Sun"),     GUI_Main.constraints(0, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Mon"),     GUI_Main.constraints(1, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Tue"),     GUI_Main.constraints(2, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Wed"),     GUI_Main.constraints(3, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Thu"),     GUI_Main.constraints(4, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Fri"),     GUI_Main.constraints(5, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        calendarPanel.add(new JLabel("Sat"),     GUI_Main.constraints(6, 1, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        for ( int i = 0; i < dayButtons.length; ++i )
        {
            dayButtons[i].addActionListener(new CalendarChosenDateChangeActionListener(i));
            calendarPanel.add(dayButtons[i], GUI_Main.constraints(i % 7, i / 7 + 2, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        }
        calendarPanel.add(new JSeparator(SwingConstants.VERTICAL),      GUI_Main.constraints(7, 0, 1, 8, 0.0, 0.0));
        for ( int i = 0; i < timeButtons.length; ++i )
        {
            timeButtons[i].addActionListener(new CalendarChosenDateChangeActionListener(-1));
            timeButtonsGroup.add(timeButtons[i]);
            calendarPanel.add(timeButtons[i], GUI_Main.constraints(i % 2 + 8, i / 2, 1, 1, 0.0, 0.0, new Insets(0, 0, 0, 0)));
        }
        calendarPanel.add(currentChosenDateLabel, GUI_Main.constraints(0, 8, 10, 1, 0.0, 0.0));
        calendarPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.BLACK, Color.BLUE), "Desired Time"));

        appointmentReasonField = new JTextArea("Specify reason here.");
        appointmentReasonPanel = new JScrollPane(appointmentReasonField);
        appointmentReasonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.BLACK, Color.BLUE), "Reason for Appointment"));

        desiredDoctorField = new JTextField();
        desiredDoctorPanel = new JPanel();
        desiredDoctorPanel.setLayout(new GridBagLayout());
        desiredDoctorPanel.add(desiredDoctorField, GUI_Main.constraints(0, 0, 1, 1, 1.0, 1.0));
        desiredDoctorPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED, Color.BLACK, Color.BLUE), "Desired Doctor"));

        submitButton = new JButton("Submit");
        cancelButton = new JButton("Cancel");

        setLayout(new GridBagLayout());
        add(new JLabel(""),         GUI_Main.constraints(0, 1, 3, 1, 1.0, 1.0));
        add(new JLabel(""),         GUI_Main.constraints(0, 2, 1, 3, 1.0, 0.0));
        add(calendarPanel,          GUI_Main.constraints(1, 2, 3, 1, 1.0, 0.4));
        add(appointmentReasonPanel, GUI_Main.constraints(1, 3, 3, 1, 1.0, 0.4));
        add(desiredDoctorPanel,     GUI_Main.constraints(1, 4, 1, 1, 1.0, 0.4));
        add(submitButton,           GUI_Main.constraints(2, 4, 1, 1, 0.4, 0.4));
        add(cancelButton,           GUI_Main.constraints(3, 4, 1, 1, 0.4, 0.4));
        add(new JLabel(""),         GUI_Main.constraints(4, 2, 1, 3, 1.0, 0.0));
        add(new JLabel(""),         GUI_Main.constraints(0, 5, 3, 1, 1.0, 1.0));
    }

    /**
     * Returns the desired time
     * @return the desired time
     */
    public Calendar getDesiredTime()
    {
        return calendarChosen;
    }

    /**
     * Returns the reason for the appointment
     * @return the reason for the appointment
     */
    public String getAppointmentReason()
    {
        return appointmentReasonField.getText();
    }

    /**
     * Returns the desired doctor
     * @return the desired doctor
     */
    public String getDesiredDoctor()
    {
        return desiredDoctorField.getText();
    }

    /**
     * Add an ActionListener to the submit button
     * @param a the ActionListener
     */
    public void addSubmitActionListener(ActionListener a)
    {
        submitButton.addActionListener(a);
    }

    /**
     * Add an ActionListener to the cancel button
     * @param a the ActionListener
     */
    public void addCancelActionListener(ActionListener a)
    {
        cancelButton.addActionListener(a);
    }

    /**
     * Clears the fields
     */
    public void clearFields()
    {
        calendarChosen = calendarView = new GregorianCalendar();
        if ( calendarChosen.get(Calendar.HOUR_OF_DAY) >= 17 )
        {
            calendarChosen.add(Calendar.DAY_OF_MONTH, 1);
            calendarChosen.set(Calendar.HOUR_OF_DAY, 0);
        }
        timeButtons[Math.max(0, (calendarChosen.get(Calendar.HOUR_OF_DAY) * 2) - 17 + (calendarChosen.get(Calendar.MINUTE) / 30))].setSelected(true);
        setDayButtons();
    }

    /**
     * An ActionListener to update the selected date and time
     */
    private class CalendarChosenDateChangeActionListener implements ActionListener
    {
        private int index;
        public CalendarChosenDateChangeActionListener(int index)
        {
            this.index = index;
        }
        public void actionPerformed(ActionEvent e)
        {
            if ( index >= 0 )
            {
                calendarChosen.set(Calendar.DAY_OF_MONTH, Integer.valueOf(dayButtons[index].getText()));
                for ( JButton i : dayButtons )
                    i.setEnabled(true);
                dayButtons[index].setEnabled(false);
                calendarChosen.set(Calendar.MONTH, calendarView.get(Calendar.MONTH));
                calendarChosen.set(Calendar.YEAR, calendarView.get(Calendar.YEAR));
            }
            if ( GregorianCalendar.getInstance().after(calendarChosen) )
            {
                calendarChosen = new GregorianCalendar();
                if ( calendarChosen.get(Calendar.HOUR_OF_DAY) >= 17 )
                {
                    calendarChosen.add(Calendar.DAY_OF_MONTH, 1);
                    calendarChosen.set(Calendar.HOUR_OF_DAY, 0);
                }
                timeButtons[Math.max(0, (calendarChosen.get(Calendar.HOUR_OF_DAY) * 2) - 17 + (calendarChosen.get(Calendar.MINUTE) / 30))].setSelected(true);
            }
            for ( int i = 0; i < timeButtons.length; ++i )
            {
                if ( timeButtons[i].isSelected() )
                {
                    calendarChosen.set(Calendar.HOUR_OF_DAY, 9 + i / 2);
                    calendarChosen.set(Calendar.MINUTE, (i % 2) * 30);
                }
            }
            currentChosenDateLabel.setText("Date/time: " + calendarChosen.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US) + " "
                                                         + calendarChosen.get(Calendar.DAY_OF_MONTH) + ", "
                                                         + calendarChosen.get(Calendar.YEAR) + " @ "
                                                         + calendarChosen.get(Calendar.HOUR_OF_DAY) + ":"
                                                         + (calendarChosen.get(Calendar.MINUTE) < 10 ? "0" + calendarChosen.get(Calendar.MINUTE)
                                                                                                     : calendarChosen.get(Calendar.MINUTE)));
            setDayButtons();
        }
    }

    /**
     * An ActionListener to update the calendarView
     */
    private class CalendarViewChangeActionListener implements ActionListener
    {
        private int field;
        private boolean value;
        public CalendarViewChangeActionListener(int field, boolean value)
        {
            this.field = field;
            this.value = value;
        }
        public void actionPerformed(ActionEvent e)
        {
            calendarView.add(field, value ? 1 : -1);
            if ( calendarView.before(new GregorianCalendar()) )
                calendarView = new GregorianCalendar();
            setDayButtons();
        }
    }

    /**
     * Sets the dayButtons based on the current calendarView month and year
     */
    public void setDayButtons()
    {
        for ( int i = 0; i < dayButtons.length; ++i )
        {
            dayButtons[i].setVisible(false);
            dayButtons[i].setEnabled(true);
        }
        for ( int i = 0; i < calendarView.getActualMaximum(Calendar.DAY_OF_MONTH); ++i )
        {
            dayButtons[i + Math.abs(7 - calendarView.get(Calendar.DAY_OF_MONTH) + calendarView.get(Calendar.DAY_OF_WEEK)) % 7].setVisible(true);
            dayButtons[i + Math.abs(7 - calendarView.get(Calendar.DAY_OF_MONTH) + calendarView.get(Calendar.DAY_OF_WEEK)) % 7].setText("" + (i + 1));
            if ( calendarView.get(Calendar.YEAR) == calendarChosen.get(Calendar.YEAR)
              && calendarView.get(Calendar.MONTH) == calendarChosen.get(Calendar.MONTH)
              && i + 1 == calendarChosen.get(Calendar.DAY_OF_MONTH) )
            {
                dayButtons[i + Math.abs(7 - calendarView.get(Calendar.DAY_OF_MONTH) + calendarView.get(Calendar.DAY_OF_WEEK)) % 7].setEnabled(false);
            }
        }
        currentMonthYearLabel.setText(calendarView.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.US) + " " + calendarView.get(Calendar.YEAR));
    }
}

